From 3ea0955bed76ef43dc49f71fd917eff9294def13 Mon Sep 17 00:00:00 2001 From: oliskoli Date: Tue, 29 Aug 2006 21:25:31 +0000 Subject: [PATCH] Add support for "Digital Mapping TrackLogs" (.trl) files. --- Makefile.in | 4 +- dmtlog.c | 719 ++++++++++++++++++++++++++++++ reference/track/dmtlog-sample.gpx | 669 +++++++++++++++++++++++++++ testo | 8 + vecs.c | 7 + 5 files changed, 1406 insertions(+), 1 deletion(-) create mode 100644 dmtlog.c create mode 100644 reference/track/dmtlog-sample.gpx diff --git a/Makefile.in b/Makefile.in index 59a4e8500..3838b60fe 100644 --- a/Makefile.in +++ b/Makefile.in @@ -53,7 +53,7 @@ FMTS=magproto.o gpx.o geo.o mapsend.o mapsource.o garmin_tables.o \ tef_xml.o maggeo.o pathaway.o vitosmt.o gdb.o bcr.o coto.o \ ignrando.o stmwpp.o msroute.o cst.o nmn4.o mag_pdb.o compegps.o \ yahoo.o unicsv.o wfff_xml.o garmin_txt.o axim_gpb.o gpssim.o \ - wbt-200.o stmsdf.o gtrnctr.o + wbt-200.o stmsdf.o gtrnctr.o dmtlog.o FILTERS=position.o duplicate.o arcdist.o polygon.o smplrout.o \ reverse_route.o sort.o stackfilter.o trackfilter.o discard.o \ @@ -305,6 +305,8 @@ delgpl.o: delgpl.c defs.h config.h queue.h gbtypes.h cet.h cet_util.h \ inifile.h discard.o: discard.c defs.h config.h queue.h gbtypes.h cet.h cet_util.h \ inifile.h filterdefs.h +dmtlog.o: dmtlog.c defs.h config.h queue.h gbtypes.h \ + zlib/zlib.h jeeps/gpsmath.h xmlgeneric.h duplicate.o: duplicate.c defs.h config.h queue.h gbtypes.h cet.h \ cet_util.h inifile.h filterdefs.h easygps.o: easygps.c defs.h config.h queue.h gbtypes.h cet.h cet_util.h \ diff --git a/dmtlog.c b/dmtlog.c new file mode 100644 index 000000000..77a0ac009 --- /dev/null +++ b/dmtlog.c @@ -0,0 +1,719 @@ +/* + + Support for Digital Mapping TrackLogs (.trl) files, + + Copyright (C) 2006 Olaf Klein, o.b.klein@t-online.de + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#include "defs.h" +#include "jeeps/gpsmath.h" +#include "xmlgeneric.h" + +#include +#include +#include + +#define MYNAME "dmtlog" + +#define DEFLATE_BUFF_SIZE 16384 + +static gbfile *fin, *fout; + +static char *xmlbin; +static waypoint *xmlwpt; +static route_head *xmltrk; +static char *xmlgrid; +static int xmldatum, datum_WGS84, datum_OSGB36; +static double xmlEasting, xmlNorthing; +static double xmlLatitude, xmlLongitude; +static double xmlAltitude; + +#if !ZLIB_INHIBITED +static int xmlbinsize; +#endif + +static char header_written; +static char *opt_index; +static int track_index, this_index; + +static +arglist_t dmtlog_args[] = { + { "index", &opt_index, + "Index of track (if more the one in source)", "1", ARGTYPE_INT, "1", NULL }, + ARG_TERMINATOR +}; + + +#if !ZLIB_INHIBITED +static xg_callback tlog3a_xgcb_version, tlog3a_xgcb_length, tlog3a_xgcb_data; + +static xg_tag_mapping tlog3a_xgcb_map[] = { + { tlog3a_xgcb_version, cb_cdata, "/CXMLSafe/Version" }, + { tlog3a_xgcb_length, cb_cdata, "/CXMLSafe/Length" }, + { tlog3a_xgcb_data, cb_cdata, "/CXMLSafe/Data" }, + { NULL, 0, NULL} +}; +#endif + +static xg_callback tlog3b_xgcb_tfna, tlog3b_xgcb_tfdes; +static xg_callback tlog3b_xgcb_wptst, tlog3b_xgcb_tptst; +static xg_callback tlog3b_xgcb_tpten, tlog3b_xgcb_wpten; +static xg_callback tlog3b_xgcb_wptid, tlog3b_xgcb_wptdt; +static xg_callback tlog3b_xgcb_wptgr, tlog3b_xgcb_wptea; +static xg_callback tlog3b_xgcb_wptno, tlog3b_xgcb_wptal; +static xg_callback tlog3b_xgcb_tptdt; + +static xg_tag_mapping tlog3b_xgcb_map[] = { + { tlog3b_xgcb_tfna, cb_cdata, "/CTrackFile/Name" }, + { tlog3b_xgcb_tfdes, cb_cdata, "/CTrackFile/Description" }, + { tlog3b_xgcb_wptst, cb_start, "/CTrackFile/CWayPoint" }, + { tlog3b_xgcb_wptid, cb_cdata, "/CTrackFile/CWayPoint/Id" }, + { tlog3b_xgcb_wptdt, cb_cdata, "/CTrackFile/CWayPoint/Datum" }, + { tlog3b_xgcb_wptgr, cb_cdata, "/CTrackFile/CWayPoint/Grid" }, + { tlog3b_xgcb_wptea, cb_cdata, "/CTrackFile/CWayPoint/Easting" }, + { tlog3b_xgcb_wptno, cb_cdata, "/CTrackFile/CWayPoint/Northing" }, + { tlog3b_xgcb_wptal, cb_cdata, "/CTrackFile/CWayPoint/Altitude" }, + { tlog3b_xgcb_wpten, cb_end, "/CTrackFile/CWayPoint" }, + { tlog3b_xgcb_tptst, cb_start, "/CTrackFile/CTrackPoint" }, + { tlog3b_xgcb_wptid, cb_cdata, "/CTrackFile/CTrackPoint/Id" }, + { tlog3b_xgcb_tptdt, cb_cdata, "/CTrackFile/CTrackPoint/Datum" }, + { tlog3b_xgcb_wptgr, cb_cdata, "/CTrackFile/CTrackPoint/Grid" }, + { tlog3b_xgcb_wptea, cb_cdata, "/CTrackFile/CTrackPoint/Easting" }, + { tlog3b_xgcb_wptno, cb_cdata, "/CTrackFile/CTrackPoint/Northing" }, + { tlog3b_xgcb_wptal, cb_cdata, "/CTrackFile/CTrackPoint/Altitude" }, + { tlog3b_xgcb_tpten, cb_end, "/CTrackFile/CTrackPoint" }, + { NULL, 0, NULL} +}; + +/* helpers */ + +static void +convert_datum(waypoint *wpt, int datum) +{ + if (datum != datum_WGS84) { + double lat = wpt->latitude; + double lon = wpt->longitude; + double alt = wpt->altitude; + GPS_Math_Known_Datum_To_WGS84_C(lat, lon, alt, + &wpt->latitude, &wpt->longitude, &wpt->altitude, + datum); + } +} + + +static void +finalize_pt(waypoint *wpt) +{ + if (strcmp(xmlgrid, "BNG") == 0) { + GPS_Math_NGENToAiry1830LatLon(xmlEasting, xmlNorthing, + &wpt->latitude, &wpt->longitude); + xmldatum = datum_OSGB36; + } + else { + wpt->latitude = xmlLatitude; + wpt->longitude = xmlLongitude; + } + wpt->altitude = xmlAltitude; + convert_datum(wpt, xmldatum); +} + +/* xml-reader callbacks */ + +#if !ZLIB_INHIBITED +static void +tlog3a_xgcb_version(const char *args, const char **unused) +{ + if (strcmp(args, "1") != 0) + fatal(MYNAME ": Unsupported file version '%s'!\n", args); +} + +static void +tlog3a_xgcb_length(const char *args, const char **unused) +{ +} + +static void +tlog3a_xgcb_data(const char *args, const char **unused) +{ + int len; + char *bin; + char *cin, *cout; + char cl, ch; + + len = strlen(args); + bin = xmalloc((len >> 1) + 1); + + cin = (char *)args; + cout = bin; + + cl = 0x10; + while (*cin) { + char c = *cin++; + + if (c == '\0') break; + else if ((c >= 'A') && (c <= 'F')) c -= 'A' - 10; + else if ((c >= 'a') && (c <= 'f')) c -= 'a' - 10; + else if ((c >= '0') && (c <= '9')) c -= '0'; + else continue; + + if (cl == 0x10) cl = c; + else { + ch = (cl << 4) | c; + *cout++ = ch; + cl = 0x10; + } + } + xmlbin = bin; + xmlbinsize = (cout - bin); +} +#endif + + +static void +tlog3b_xgcb_tfna(const char *args, const char **unused) +{ + if (xmltrk == NULL) { + xmltrk = route_head_alloc(); + track_add_head(xmltrk); + } + xmltrk->rte_name = strdup(args); +} + + +static void +tlog3b_xgcb_tfdes(const char *args, const char **unused) +{ + if (xmltrk == NULL) { + xmltrk = route_head_alloc(); + track_add_head(xmltrk); + } + xmltrk->rte_desc = strdup(args); +} + + +static void +tlog3b_xgcb_wptst(const char *args, const char **unused) +{ + xmlwpt = waypt_new(); + xmldatum = datum_WGS84; +} + + +static void +tlog3b_xgcb_tptst(const char *args, const char **unused) +{ + xmlwpt = waypt_new(); + xmldatum = datum_WGS84; +} + + +static void +tlog3b_xgcb_tpten(const char *args, const char **unused) +{ + finalize_pt(xmlwpt); + + if (xmltrk == NULL) { + xmltrk = route_head_alloc(); + track_add_head(xmltrk); + } + track_add_wpt(xmltrk, xmlwpt); + xmlwpt = NULL; +} + + +static void +tlog3b_xgcb_wptid(const char *args, const char **unused) +{ + if (*args) + xmlwpt->shortname = xstrdup(args); +} + + +static void +tlog3b_xgcb_wptdt(const char *args, const char **unused) +{ + xmldatum = GPS_Lookup_Datum_Index(args); +} + + +static void +tlog3b_xgcb_wptgr(const char *args, const char **unused) +{ + if (xmlgrid != NULL) { + if (strcmp(xmlgrid, args) == 0) return; + xfree(xmlgrid); + } + xmlgrid = xstrdup(args); +} + + +static void +tlog3b_xgcb_wptno(const char *args, const char **unused) +{ + xmlNorthing = atof(args); +} + + +static void +tlog3b_xgcb_wptea(const char *args, const char **unused) +{ + xmlEasting = atof(args); +} + + +static void +tlog3b_xgcb_wptal(const char *args, const char **unused) +{ + xmlAltitude = atof(args); +} + + +static void +tlog3b_xgcb_tptdt(const char *args, const char **unused) +{ + xmldatum = GPS_Lookup_Datum_Index(args); +} + + +static void +tlog3b_xgcb_wpten(const char *args, const char **unused) +{ + finalize_pt(xmlwpt); + waypt_add(xmlwpt); + xmlwpt = NULL; +} + + +static int +read_datum(gbfile *f) +{ + int res; + char *d, *g; + + d = gbfgetpstr(f); + g = gbfgetpstr(f); + + res = GPS_Lookup_Datum_Index(d); + + if (*g && (strcmp(d, g) != 0)) { + fatal(MYNAME ": Unsupported combination of datum '%s' and grid '%s'!\n", + d, g); + } + xfree(d); + xfree(g); + + return res; +} + + +static void +read_CTrackFile(const int version) +{ + char buf[128]; + gbuint32 ver; + gbint32 tcount, wcount; + gbint16 u1; + gbint32 ux; + route_head *track; + int i; + int datum; + + u1 = gbfgetint16(fin); + + gbfread(buf, 1, 10, fin); + if ((u1 != 0x0a) || (strncmp("CTrackFile", buf, 10) != 0)) + fatal(MYNAME ": Unknown or invalid track file.\n"); + + if (version == 8) { + for (i = 1; i <= 9; i++) + gbfread(buf, 1, 4, fin); + } + ver = gbfgetint32(fin); + if (ver != version) + fatal(MYNAME ": Unknown or invalid track file (%d).\n", ver); + + ux = gbfgetint32(fin); // Unknown 2 + ux = gbfgetint32(fin); // Unknown 3 + ux = gbfgetint32(fin); // Unknown 4 + + track = route_head_alloc(); + track_add_head(track); + + /* S1 .. S9: comments, hints, jokes, aso */ + for (i = 0; i < 9; i++) { + int c = gbfgetc(fin); + gbfseek(fin, c, SEEK_CUR); + } + + tcount = gbfgetint32(fin); + if (tcount > 0) { + datum = read_datum(fin); + if (version == 8) { + int len; + + gbfread(buf, 1, 4, fin); + len = gbfgetint16(fin); + gbfseek(fin, len, SEEK_CUR); + } + } + + while (tcount > 0) + { + waypoint *wpt; + + tcount--; + + if (version == 8) + datum = read_datum(fin); + + wpt = waypt_new(); + + wpt->latitude = gbfgetdbl(fin); + wpt->longitude = gbfgetdbl(fin); + wpt->altitude = gbfgetdbl(fin); + + convert_datum(wpt, datum); + + track_add_wpt(track, wpt); + + if (version == 8) + gbfseek(fin, 34, SEEK_CUR); + } + + wcount = gbfgetint32(fin); + + if (wcount == 0) return; + + if (version == 8) { + warning(MYNAME ": We don't yet support waypoints for this file version!\n"); + return; + } + + datum = read_datum(fin); + + while (wcount > 0) { + waypoint *wpt; + gbint32 namect, i; + + wcount--; + + if (version == 8) + datum = read_datum(fin); + + wpt = waypt_new(); + + wpt->latitude = gbfgetdbl(fin); + wpt->longitude = gbfgetdbl(fin); + wpt->altitude = gbfgetdbl(fin); + + convert_datum(wpt, datum); + + namect = gbfgetint32(fin); + + // variants of shortname + + for (i = 0; i < namect; i++) { + char *name = gbfgetpstr(fin); + if (name && *name) { + switch(i) { + case 0: wpt->description = xstrdup(name); break; + case 1: wpt->shortname = xstrdup(name); break; + } + } + xfree(name); + } + if (version == 8) + gbfseek(fin, 34, SEEK_CUR); + + waypt_add(wpt); + } +} + + +#if !ZLIB_INHIBITED + +static int +inflate_buff(const char *buff, const size_t size, char **out_buff) +{ + int res = Z_OK; + z_stream strm; + char out[DEFLATE_BUFF_SIZE]; + char *cout = NULL; + gbuint32 bytes = 0; + gbuint32 have; + + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = 0; + strm.next_in = Z_NULL; + + res = inflateInit(&strm); + if (res != Z_OK) { + return res; + } + + strm.avail_in = size; + strm.next_in = (void *)buff; + + do { + strm.avail_out = DEFLATE_BUFF_SIZE; + strm.next_out = (void *)out; + res = inflate(&strm, Z_NO_FLUSH); + + switch (res) { + case Z_NEED_DICT: + res = Z_DATA_ERROR; /* and fall through */ + case Z_DATA_ERROR: + case Z_MEM_ERROR: + (void)inflateEnd(&strm); + return res; + } + have = DEFLATE_BUFF_SIZE - strm.avail_out; + if (have > 0) { + cout = xrealloc(cout, bytes + have); + memcpy(cout+bytes, out, have); + bytes+=have; + } + } while (strm.avail_out == 0); + + *out_buff = cout; + return res; +} + + +static void +read_CXMLSafe(void) +{ + char *xmlstr = NULL; + + xmlbin = NULL; + xmlbinsize = 0; + + xml_init(fin->name, tlog3a_xgcb_map, NULL); + xml_read(); + xml_deinit(); + + if (xmlbin != NULL) { + inflate_buff(xmlbin, xmlbinsize, &xmlstr); + xfree(xmlbin); + + xml_init(NULL, tlog3b_xgcb_map, NULL); + xml_readstring(xmlstr); + xml_deinit(); + + xfree(xmlstr); + } +} + +#endif + +static void +read_XML(void) +{ + xml_init(fin->name, tlog3b_xgcb_map, NULL); + xml_read(); + xml_deinit(); + + return; +} + +/******************************************************************************* +* %%% global callbacks called by gpsbabel main process %%% * +*******************************************************************************/ + +static void +dmtlog_rd_init(const char *fname) +{ + fin = gbfopen_le(fname, "rb", MYNAME); + + datum_OSGB36 = GPS_Lookup_Datum_Index("OSGB36"); + datum_WGS84 = GPS_Lookup_Datum_Index("WGS84"); + + xmlbin = NULL; + xmltrk = NULL; + xmlwpt = NULL; + xmlgrid = NULL; +} + +static void +dmtlog_rd_deinit(void) +{ + gbfclose(fin); + if (xmlgrid != NULL) xfree(xmlgrid); +} + +static void +dmtlog_read(void) +{ + switch(gbfgetuint32(fin)) { + + case 0x4FFFF: + read_CTrackFile(4); + break; + + case 0x8FFFF: + read_CTrackFile(8); + break; + + case 0x4d58433c: +#if !ZLIB_INHIBITED + read_CXMLSafe(); +#else + fatal(MYNAME ": Zlib was not included in this build.\n"); +#endif + break; + case 0x7254433c: + read_XML(); + break; + + default: + fatal(MYNAME ": Unknown or unsupported file type.\n"); + } +} + +static void +dmtlog_wr_init(const char *fname) +{ + fout = gbfopen_le(fname, "wb", MYNAME); +} + +static void +dmtlog_wr_deinit(void) +{ + gbfclose(fout); +} + +static void +write_header(const route_head *trk) +{ + int count, i; + char *cout; + const char ZERO = '\0'; + + header_written = 1; + + count = 0; + if (trk != NULL) { + queue *curr, *prev; + QUEUE_FOR_EACH(&trk->waypoint_list, curr, prev) count++; + } + gbfputpstr(trk && trk->rte_name && *trk->rte_name ? trk->rte_name : "Name", fout); + + xasprintf(&cout, "%d trackpoints and %d waypoints", count, waypt_count()); + gbfputpstr(cout, fout); + xfree(cout); + + for (i = 3; i <= 8; i++) gbfputc(ZERO, fout); + gbfputpstr("GPSBabel", fout); + gbfputint32(count, fout); + if (count > 0) { + gbfputpstr("WGS84", fout); + gbfputpstr("WGS84", fout); + } +} + +static void +track_hdr_cb(const route_head *trk) +{ + + this_index++; + if (this_index != track_index) return; + write_header(trk); +} + +static void +track_tlr_cb(const route_head *trk) +{ +} + +static void +track_wpt_cb(const waypoint *wpt) +{ + if (this_index != track_index) return; + + gbfputdbl(wpt->latitude, fout); + gbfputdbl(wpt->longitude, fout); + gbfputdbl(wpt->altitude, fout); +} + +static void +wpt_cb(const waypoint *wpt) +{ + int names; + + gbfputdbl(wpt->latitude, fout); + gbfputdbl(wpt->longitude, fout); + gbfputdbl(wpt->altitude, fout); + + names = 1; + if (wpt->description && *wpt->description) names = 2; + gbfputint32(names, fout); + if (names > 1) gbfputpstr(wpt->description, fout); + gbfputpstr(wpt->shortname && *wpt->shortname ? wpt->shortname : "Name", fout); +} + +static void +dmtlog_write(void) +{ + track_index = atoi(opt_index); + /* ... validate index */ + + gbfputint32(0x4FFFF, fout); + gbfputuint16(0x0A, fout); + gbfputs("CTrackFile", fout); + gbfputint32(4, fout); + gbfputint32(1, fout); + gbfputint32(0x100001, fout); + gbfputuint32((const gbuint32)gpsbabel_now, fout); + + header_written = 0; + this_index = 0; + track_disp_all(track_hdr_cb, track_tlr_cb, track_wpt_cb); + if (!header_written) + write_header(NULL); + gbfputint32(waypt_count(), fout); + if (waypt_count() > 0) { + gbfputpstr("WGS84", fout); + gbfputpstr("WGS84", fout); + waypt_disp_all(wpt_cb); + } +} + +/**************************************************************************/ + +ff_vecs_t dmtlog_vecs = { + ff_type_file, + { + ff_cap_read | ff_cap_write /* waypoints */, + ff_cap_read | ff_cap_write /* tracks */, + ff_cap_none /* routes */ + }, + dmtlog_rd_init, + dmtlog_wr_init, + dmtlog_rd_deinit, + dmtlog_wr_deinit, + dmtlog_read, + dmtlog_write, + NULL, + dmtlog_args, + CET_CHARSET_ASCII, 0 + +}; + +/**************************************************************************/ diff --git a/reference/track/dmtlog-sample.gpx b/reference/track/dmtlog-sample.gpx new file mode 100644 index 000000000..fc52a5c6f --- /dev/null +++ b/reference/track/dmtlog-sample.gpx @@ -0,0 +1,669 @@ + + + + + + 44.586548 + 5066 + 5066 + 5066 + + + 57.607200 + 5067 + 5067 + 5067 + + + 44.826904 + 5096 + 5096 + 5096 + + + 50.594727 + 5142 + 5142 + 5142 + + + 127.711200 + 5156 + 5156 + 5156 + + + 96.926400 + 5224 + 5224 + 5224 + + + 82.600800 + 5229 + 5229 + 5229 + + + 82.905600 + 5237 + 5237 + 5237 + + + 66.696655 + 5254 + 5254 + 5254 + + + 74.627442 + 5258 + 5258 + 5258 + + + 65.254761 + 5264 + 5264 + 5264 + + + 77.419200 + 526708 + 526708 + 526708 + + + 74.676000 + 526750 + 526750 + 526750 + + + 78.713135 + 527614 + 527614 + 527614 + + + 78.713135 + 527631 + 527631 + 527631 + + + 68.275200 + 5278 + 5278 + 5278 + + + 64.008000 + 5289 + 5289 + 5289 + + + 52.997925 + 5374FIRE + 5374FIRE + 5374FIRE + + + 56.388000 + 5376 + 5376 + 5376 + + + 56.388000 + 6006 + 600698 + 600698 + + + 46.028564 + 6006BLUE + 6006BLUE + 6006BLUE + + + 37.616943 + 6014MEADOW + 6014MEADOW + 6014MEADOW + + + 56.388000 + 6029 + 6029 + 6029 + + + 50.292000 + 6053 + 6053 + 6053 + + + 25.603200 + 6066 + 6066 + 6066 + + + 34.442400 + 6067 + 6067 + 6067 + + + 30.480000 + 6071 + 6071 + 6071 + + + 15.240000 + 6073 + 6073 + 6073 + + + 37.795200 + 6084 + 6084 + 6084 + + + 64.008000 + 6130 + 6130 + 6130 + + + 64.008000 + 6131 + 6131 + 6131 + + + 62.788800 + 6153 + 6153 + 6153 + + + 55.473600 + 6171 + 6171 + 6171 + + + 62.484000 + 6176 + 6176 + 6176 + + + 62.179200 + 6177 + 6177 + 6177 + + + 69.799200 + 6272 + 6272 + 6272 + + + 73.152000 + 6272 + 6272 + 6272 + + + 70.104000 + 6278 + 6278 + 6278 + + + 57.564209 + 6280 + 6280 + 6280 + + + 66.696655 + 6283 + 6283 + 6283 + + + 72.945191 + 6289 + 6289 + 6289 + + + 72.847200 + 6297 + 6297 + 6297 + + + 53.644800 + 6328 + 6328 + 6328 + + + 43.891200 + 6354 + 6354 + 6354 + + + 48.768000 + 635722 + 635722 + 635722 + + + 49.072800 + 635783 + 635783 + 635783 + + + 62.484000 + 6373 + 6373 + 6373 + + + 3.962400 + 6634 + 6634 + 6634 + + + 13.411200 + 6979 + 6979 + 6979 + + + 34.012085 + 6997 + 6997 + 6997 + + + 87.782400 + BEAR HILL + BEAR HILL TOWER + BEAR HILL TOWER + + + 23.469600 + BELLEVUE + BELLEVUE + BELLEVUE + + + 43.384766 + 6016 + Bike Loop Connector + Bike Loop Connector + + + 89.916000 + 5236BRIDGE + Bridge + Bridge + + + 55.473600 + 5376BRIDGE + Bridge + Bridge + + + 52.730400 + 6181CROSS + Crossing + Crossing + + + 45.110400 + 6042CROSS + Crossing + Crossing + + + DARKHOLLPO + Dark Hollow Pond + Dark Hollow Pond + + + 56.083200 + 6121DEAD + Dead End + Dead End + + + 117.043200 + 5179DEAD + Dead End + Dead End + + + 69.494400 + 5299DEAD + Dead End + Dead End + + + 56.997600 + 5376DEAD + Dead End + Dead End + + + 46.939200 + 6353DEAD + Dead End + Dead End + + + 61.264800 + 6155DEAD + Dead End + Dead End + + + 110.947200 + GATE14 + Gate 14 + Gate 14 + + + 77.724000 + GATE16 + Gate 16 + Gate 16 + + + 65.836800 + GATE17 + Gate 17 + Gate 17 + + + 57.302400 + GATE19 + Gate 19 + Gate 19 + + + 49.377600 + GATE21 + Gate 21 + Gate 21 + + + 81.076800 + GATE24 + Gate 24 + Gate 24 + + + 21.515015 + GATE5 + Gate 5 + Gate 5 + + + 26.561890 + GATE6 + Gate 6 + Gate 6 + + + 32.004000 + 6077LOGS + Log Crossing + Log Crossing + + + 119.809082 + 5148NANEPA + Nanepashemet Road Crossing + Nanepashemet Road Crossing + + + 73.761600 + 5267OBSTAC + Obstacle + Obstacle + + + 45.307495 + PANTHRCAVE + Panther Cave + Panther Cave + + + 77.992066 + 5252PURPLE + Purple Rock Hill + Purple Rock Hill + + + 67.970400 + 5287WATER + Reservoir + Reservoir + + + 81.076800 + 5239ROAD + Road + Road + + + 67.360800 + 5278ROAD + Road + Road + + + 53.949600 + 5058ROAD + ROAD CROSSING + ROAD CROSSING + + + 69.799200 + SHEEPFOLD + Sheepfold Parking Lot + Sheepfold Parking Lot + + + 64.008000 + SOAPBOX + Soap Box Derby Track + Soap Box Derby Track + + + 64.533692 + 5376STREAM + Stream Crossing + Stream Crossing + + + 61.649902 + 5144SUMMIT + Summit + Summit + + + 67.360800 + 5150TANK + WATER TANK + WATER TANK + + + + + 1.000000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 2.000000 + + + + + 1.000000 + + + + + + + + + + + 2.000000 + + + 1.000000 + + + 1.000000 + + + + + 2.000000 + + + + + + + + + + + + + 6.000000 + + + 2.000000 + + + + + + + + + + + 1.000000 + + + + + + + 6.000000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 7.000000 + + + + + + + + + + + + + + + + + + diff --git a/testo b/testo index 9000ea3a4..cc28d0f24 100755 --- a/testo +++ b/testo @@ -1100,6 +1100,14 @@ compare ${TMPDIR}/stmsdf-route.sdf ${REFERENCE}/route/stmsdf-route.sdf ${PNAME} -i stmsdf -f ${TMPDIR}/stmsdf-track.sdf -f ${TMPDIR}/stmsdf-route.sdf -o garmin_txt,prec=2 -F ${TMPDIR}/stmsdf.txt compare ${TMPDIR}/stmsdf.txt ${REFERENCE}/stmsdf.txt +# +# Digital Mapping Tracklogs +# +rm -f ${TMPDIR}/dmtlog* +${PNAME} -i gpx -f ${REFERENCE}/expertgps.gpx -o dmtlog -F ${TMPDIR}/dmtlog-sample.trl +${PNAME} -i dmtlog -f ${TMPDIR}/dmtlog-sample.trl -o gpx -F ${TMPDIR}/dmtlog-sample.gpx +compare ${TMPDIR}/dmtlog-sample.gpx ${REFERENCE}/track/dmtlog-sample.gpx + # # gzipped file i/o # diff --git a/vecs.c b/vecs.c index e39af20c5..32aa0f6bd 100644 --- a/vecs.c +++ b/vecs.c @@ -110,6 +110,7 @@ extern ff_vecs_t yahoo_vecs; extern ff_vecs_t wbt_svecs; extern ff_vecs_t wbt_fvecs; extern ff_vecs_t gtc_vecs; +extern ff_vecs_t dmtlog_vecs; static vecs_t vec_list[] = { @@ -600,6 +601,12 @@ vecs_t vec_list[] = { "Garmin Training Center" "xml" }, + { + &dmtlog_vecs, + "dmtlog", + "Digital Mapping TrackLogs (.trl)", + "trl" + }, { NULL, NULL, -- 2.30.2